package com.eastsunsoft.swordfish.ucms.controller;

import com.eastsunsoft.swordfish.common.ApiConstant;
import com.eastsunsoft.swordfish.common.ResJson;
import com.eastsunsoft.swordfish.common.SwordfishException;
import com.eastsunsoft.swordfish.ucms.common.UcmsConstant;
import com.eastsunsoft.swordfish.ucms.config.UcmsConfig;
import com.eastsunsoft.swordfish.ucms.dto.UserDTO;
import com.eastsunsoft.swordfish.ucms.service.UserService;
import com.eastsunsoft.swordfish.ucms.vo.UserReqVO;
import com.google.common.base.Preconditions;
import io.jsonwebtoken.*;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <h1>UserController</h1>
 * </br>
 *
 * @author donny
 * @date 11/09/2017
 */
@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @Autowired
    private UcmsConfig ucmsConfig;

    @Autowired
    private RedisTemplate<String, Map<String, String>> stringMapRedisTemplate;

    public String user() {
//        try {
//            Thread.sleep(10000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        String requestId = request.getHeader("X-Request-ID");
//        String Authorization = request.getHeader("Authorization");
//        System.out.println(requestId);
//        System.out.println(Authorization);
        return "{\"username\":\"test\", \"age\":14, \"comment\":\"备注\"}";
    }

    @PostMapping("/post")
    public String post(@RequestBody UserReqVO user) {
        System.out.println(user);
        return "ok";
    }

    @ApiOperation(value = "获取token", notes = "根据用户登录信息／密码")
    @PostMapping(value = "/token", produces= MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResJson token(@RequestBody UserReqVO userReqVO) {
        ResJson resJson = new ResJson();

        Preconditions.checkArgument(!StringUtils.isEmpty(userReqVO.getUsername()), ApiConstant.ERRCODE_PARAMS_INVALID);
        Preconditions.checkArgument(!StringUtils.isEmpty(userReqVO.getUserpwd()), ApiConstant.ERRCODE_PARAMS_INVALID);

        UserDTO userDTO = userService.getByAccountAndPwd(userReqVO.getUsername(), userReqVO.getUserpwd());
        System.out.println(userDTO);
        if (userDTO == null) {
            // user not match!
            throw new SwordfishException(UcmsConstant.ERR_USER_NOT_MATCH);
        }

        List<String> userRoles = userService.listRolesByID(userDTO.getId());
        Map<String, String> userInfoMap = new HashMap<>();
        for (String userRole : userRoles) {
            userInfoMap.put(userRole, userRole);
        }
        userInfoMap.put(UcmsConstant.USER_LOGIN_DATETIME, LocalDateTime.now().toString());

        stringMapRedisTemplate.opsForHash().putAll(UcmsConstant.PREFIX_USER + userDTO.getId(), userInfoMap);
        // TODO: 获取超时时间(DB)
        stringMapRedisTemplate.expire(UcmsConstant.PREFIX_USER + userDTO.getId(), 30, TimeUnit.MINUTES);

        String role;
        if (Objects.equals(userDTO.getAdmin(), ApiConstant.YES)) {
            role = UcmsConstant.ROLE_ADMIN;
        } else if (Objects.equals(userDTO.getCompanyAdmin(), ApiConstant.YES)) {
            role = UcmsConstant.ROLE_COMPANY_ADMIN;
        } else {
            role = UcmsConstant.ROLE_USER;
        }

        Date now = new Date();
        LocalDateTime expireDateTime = LocalDateTime.ofInstant(now.toInstant(), ZoneOffset.of("+08:00")).plusMinutes(30);
        Map<String, Object> claims = new HashMap<>();
        claims.put(UcmsConstant.CLAIM_ROLE, role);
        String compactJws = Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(now)
                .setExpiration(Date.from(expireDateTime.toInstant(ZoneOffset.of("+08:00"))))
                .setSubject(userDTO.getId().toString())
                .signWith(SignatureAlgorithm.HS512, ucmsConfig.getJwt().getSecurity())
                .compact();
        resJson.setBody(compactJws);
        return resJson;
    }

    @GetMapping(value = "/auth", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResJson auth(String authToken, String uri, String method) {
        ResJson resJson = new ResJson();
        resJson.setBody(ApiConstant.STRING_TRUE);
        try {
            Jws<Claims> jws = Jwts.parser().setSigningKey(ucmsConfig.getJwt().getSecurity()).parseClaimsJws(authToken);
            //OK, we can trust this JWT
            String userId = jws.getBody().getSubject();
            String role = (String) jws.getBody().get(UcmsConstant.CLAIM_ROLE);

            if (UcmsConstant.ROLE_ADMIN.equals(role)) {
                // 系统管理员，放行
                return resJson;
            }

            // 获取uri对应的权限(redis)
            String uriRole = (String) stringMapRedisTemplate.opsForHash().get(UcmsConstant.UCMS_ROLES, uri + ":" + method.toLowerCase());
            if (StringUtils.isEmpty(uriRole)) {
                // not found
                throw new SwordfishException(ApiConstant.ERR_NO_PERMISSION);
            }

            // 根据useId，验证该用户是否具有对应uri权限(redis)
            if (!stringMapRedisTemplate.opsForHash().hasKey(UcmsConstant.PREFIX_USER + userId, uriRole)) {
                // no perm
                throw new SwordfishException(ApiConstant.ERR_NO_PERMISSION);
            }
        } catch (SignatureException e) {
            throw new SwordfishException(ApiConstant.ERRCODE_ACCESSTOKEN_INVALID_INT + ":" + ApiConstant.ERRMSG_INVALID_HEADER);
        } catch (ExpiredJwtException e) {
            throw new SwordfishException(ApiConstant.ERR_ACCESSTOKEN_EXPIRED);
        }

        return resJson;
    }
}